package org.lex.game.sudoku.util;

import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;

import javax.swing.SwingUtilities;

import ms.sudoku.util.IntSet;

import org.lex.game.sudoku.model.CheckResult;
import org.lex.game.sudoku.model.SudokuModel;
import org.lex.game.sudoku.model.SudokuModelListener;
import org.lex.game.sudoku.model.SudokuModelListener.Cause;
import org.lex.game.sudoku.model.builder.SudokuBuilder;

public class SyncSudokuModel implements SudokuModel {
	private final SudokuModel model;

	public SyncSudokuModel(SudokuModel model) {
		super();
		this.model = model;
	}

	public void newGame(final SudokuBuilder builder) {
		run(new Runnable() {
			@Override
			public void run() {
				model.newGame(builder);
			}
		});
	}

	@Override
	public String dump() {
		return this.model.dump();
	}

	@Override
	public int getCurrentEmptyCellsCount() {
		return model.getCurrentEmptyCellsCount();
	}

	public void reset() {
		run(new Runnable() {
			@Override
			public void run() {
				model.reset();
			}
		});
	}

	@Override
	public IntSet getHints(int row, int column) {
		return model.getHints(row, column);
	}

	public boolean isCompleted() {
		return model.isCompleted();
	}

	public int getGridSize() {
		return model.getGridSize();
	}

	public int getBoxSize() {
		return model.getBoxSize();
	}

	public int getOriginalEmptyCellsCount() {
		return model.getOriginalEmptyCellsCount();
	}

	public int get(int row, int column) {
		return model.get(row, column);
	}

	public boolean isEditable(int row, int column) {
		return model.isEditable(row, column);
	}

	@Override
	public int[][] toArray() {
		return model.toArray();
	}

	public void set(final Cause cause, final int row, final int column, final int value) {
		run(new Runnable() {
			@Override
			public void run() {
				model.set(cause, row, column, value);
			}
		});
	}

	public CheckResult checkCell(int row, int column, boolean findAllInvalid) {
		return model.checkCell(row, column, findAllInvalid);
	}

	public CheckResult checkAll(boolean findAllInvalid) {
		return model.checkAll(findAllInvalid);
	}

	@Override
	public boolean checkCanFillWith(int row, int col, int num) {
		return model.checkCanFillWith(row, col, num);
	}

	public void addListener(SudokuModelListener listener) {
		model.addListener(listener);
	}

	public void removeListener(SudokuModelListener listener) {
		model.removeListener(listener);
	}

	private void run(Runnable run) {
		if (EventQueue.isDispatchThread()) {
			run.run();
		} else {
			try {
				SwingUtilities.invokeAndWait(run);
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
